from sqlalchemy.future import select
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Optional, List, Dict, Any
from server.db.models.user import User, Role
from server.schemas.user import UserCreate, UserUpdate
from passlib.context import CryptContext
import uuid
from datetime import datetime

class UserRepository:
    def __init__(self, db: AsyncSession):
        self.db = db
        self.pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

    async def create_user(self, user_in: UserCreate) -> User:
        """创建新用户"""
        # 生成盐值和哈希密码
        salt = str(uuid.uuid4())[:8]
        hashed_password = self.pwd_context.hash(user_in.password + salt)

        # 创建用户对象
        db_obj = User(
            username=user_in.username,
            email=user_in.email,
            phone=user_in.phone,
            hashed_password=hashed_password,
            salt=salt,
            status=1,
            remark=user_in.remark
        )

        # 添加角色
        if user_in.role_ids:
            roles = await self.db.execute(
                select(Role).where(Role.id.in_(user_in.role_ids))
            )
            db_obj.roles = roles.scalars().all()

        self.db.add(db_obj)
        await self.db.commit()
        await self.db.refresh(db_obj)
        return db_obj

    async def get_user_by_id(self, user_id: int) -> Optional[User]:
        """通过ID获取用户"""
        result = await self.db.execute(
            select(User).where(User.id == user_id)
        )
        return result.scalars().first()

    async def get_user_by_username(self, username: str) -> Optional[User]:
        """通过用户名获取用户"""
        result = await self.db.execute(
            select(User).where(User.username == username)
        )
        return result.scalars().first()

    async def get_user_by_email(self, email: str) -> Optional[User]:
        """通过邮箱获取用户"""
        result = await self.db.execute(
            select(User).where(User.email == email)
        )
        return result.scalars().first()

    async def get_users(self, skip: int = 0, limit: int = 100) -> List[User]:
        """获取用户列表"""
        result = await self.db.execute(
            select(User).offset(skip).limit(limit)
        )
        return result.scalars().all()

    async def update_user(self, user_id: int, user_in: UserUpdate) -> Optional[User]:
        """更新用户信息"""
        user = await self.get_user_by_id(user_id)
        if not user:
            return None

        update_data = user_in.dict(exclude_unset=True)

        # 如果更新密码
        if "password" in update_data:
            update_data["salt"] = str(uuid.uuid4())[:8]
            update_data["hashed_password"] = self.pwd_context.hash(
                update_data.pop("password") + update_data["salt"]
            )

        # 更新角色
        if "role_ids" in update_data:
            role_ids = update_data.pop("role_ids")
            if role_ids:
                roles = await self.db.execute(
                    select(Role).where(Role.id.in_(role_ids))
                )
                user.roles = roles.scalars().all()
            else:
                user.roles = []

        # 更新其他字段
        for key, value in update_data.items():
            setattr(user, key, value)

        user.updated_at = datetime.utcnow()
        await self.db.commit()
        await self.db.refresh(user)
        return user

    async def delete_user(self, user_id: int) -> bool:
        """删除用户"""
        user = await self.get_user_by_id(user_id)
        if not user:
            return False

        await self.db.delete(user)
        await self.db.commit()
        return True

    async def authenticate(self, username: str, password: str) -> Optional[User]:
        """用户认证"""
        user = await self.get_user_by_username(username)
        if not user:
            return None

        # 验证密码
        if not self.pwd_context.verify(password + user.salt, user.hashed_password):
            return None

        # 更新最后登录时间
        user.last_login_at = datetime.utcnow()
        await self.db.commit()
        await self.db.refresh(user)
        return user

    async def get_user_roles(self, user_id: int) -> List[Role]:
        """获取用户角色"""
        user = await self.get_user_by_id(user_id)
        if not user:
            return []
        return user.roles

    async def user_exists(self, username: str = None, email: str = None) -> bool:
        """检查用户是否存在"""
        if username:
            user = await self.get_user_by_username(username)
            if user:
                return True
        if email:
            user = await self.get_user_by_email(email)
            if user:
                return True
        return False